#include <vector>
#include <iostream>
#include <semaphore.h>
#include "LockGuard.hpp"
using namespace std;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap)
        : _cap(cap), _ring_queue(cap)
    {
        sem_init(&_room_sem, 0, _cap); // 对信号量进行初始化
        sem_init(&_data_sem, 0, 0);

        pthread_mutex_init(&_product_mutex, nullptr); // 对锁进行初始化
        pthread_mutex_init(&_consume_mutex, nullptr);
    }
    ~RingQueue()
    {
        sem_destroy(&_room_sem); // 销毁信号量
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_product_mutex); // 销毁锁
        pthread_mutex_destroy(&_consume_mutex);
    }

    // 生产数据，将数据放到队列中
    void product(const T &data, const string &name)
    {
        P(_room_sem);         // 申请一个信号量
        lock(_product_mutex); // 加锁

        cout << name << "生产了一个数据" << endl;
        _ring_queue[_product_step++] = data;
        _product_step %= _cap;

        unlock(_product_mutex);
        V(_data_sem);
    }

    // 消费数据：将数据从队列中拿出来
    void consume(T *data, const string &name)
    {
        P(_data_sem);
        lock(_consume_mutex);

        cout << name << "消费了一个数据" << endl;
        *data = _ring_queue[_consume_step++];
        _consume_step %= _cap;

        unlock(_consume_mutex);
        V(_room_sem);
    }
    void P(sem_t &sem) //--申请
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem) //++释放
    {
        sem_post(&sem);
    }
    void lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void unlock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

private:
    vector<T> _ring_queue;
    int _cap;

    int _consume_step = 0;
    int _product_step = 0;

    sem_t _room_sem; // 信号量
    sem_t _data_sem;

    pthread_mutex_t _product_mutex; // 锁
    pthread_mutex_t _consume_mutex;
};